package com.xbongbong.pro.message.listener;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.NamedThreadFactory;
import com.xbongbong.paas.toolbox.util.OkHttpUtil;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.sms.model.SmsStatusModel;
import com.xbongbong.saas.domain.entity.SmsStatusEntity;
import com.xbongbong.saas.enums.SmsStatusEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author youli.chen
 * @version v1.0
 * @description: 短信定时更新短信状态任务
 * @date 2019/3/26 15:21
 * @since v1.0
 */
@WebListener
public class SmsUpdateStatusListener implements ServletContextListener {

    private static final Logger LOG = LoggerFactory.getLogger(SmsUpdateStatusListener.class);

    private SmsStatusModel smsStatusModel;

    /**
     * 2.5拉取状态报告
     */
    private static final String GET_STATUS_URI = "http://smssh1.253.com/msg/pull/report";

    /**
     * 限制最大线程数10
     */
    private ExecutorService executor = new ThreadPoolExecutor(0, 10,
            60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(1024),
            new NamedThreadFactory("msg-253-sms"),
            new ThreadPoolExecutor.CallerRunsPolicy());

    private ScheduledExecutorService executorLoop = null;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext context = sce.getServletContext();
        ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
        smsStatusModel = (SmsStatusModel) ctx.getBean("smsStatusModel");
        try {
            LOG.info("--------开始更新短信状态---------");
            smsUpdateStatusTask();
            LOG.info("--------结束更新短信状态---------");
        } catch (Exception e) {
            LOG.error("taskInsertQueue 启动失败", e);
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        try {
            loopClose();
        } catch (Exception e) {
            LOG.error("taskInsertQueue 停止失败", e);
        }
    }

    /**
     * @throws Exception
     * @author tzl
     * @time 2016年12月6日 上午10:32:49
     */
    public void loopClose() throws Exception {
        LOG.info("loop close");
        executorLoop.shutdown();
        executorLoop = null;
    }

    public void smsUpdateStatusTask() throws Exception {
        if (executorLoop == null) {
            executorLoop = Executors.newScheduledThreadPool(1);
        }
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                Integer now = DateUtil.getInt();
                Integer startTime = DateUtil.getTodayInt() - 60;
                Map<String, Object> param = new HashMap<>(16);
                param.put("del", DelEnum.NORMAL.getDel());
                List<Integer> statusIn = Arrays.asList(SmsStatusEnum.NO_SEND.getCode(), SmsStatusEnum.SEND_ING.getCode());
                param.put("statusIn", statusIn);
                param.put("startTime", startTime);
                param.put("endTime", now);
                List<SmsStatusEntity> lists = smsStatusModel.findEntitys(param);
                //入队列
                for (SmsStatusEntity entity : lists) {
                    updateSmsStatus(entity);
                }
            }
        };
        LOG.info("loop start");
        executorLoop.scheduleWithFixedDelay(runnable, 0, 1, TimeUnit.MINUTES);
    }

    private void updateSmsStatus(final SmsStatusEntity entity) {
        executor.submit(new Runnable() {
            @Override
            public void run() {
                JSONObject ret = null;
                while (true) {
                    // 2：创蓝的营销账号
                    if (Objects.equals(entity.getSendApi(), 2)) {
                        ret = getStatus();
                        // 1: 创蓝的回调账号
                    } else if (Objects.equals(entity.getSendApi(), 1)) {
                        ret = getStatusMsg();
                    }

                    if (ret == null) {
                        break;
                    }
                    JSONArray retArray = ret.getJSONArray("result");
                    if (retArray == null || retArray.isEmpty()) {
                        break;
                    }
                    for (int i = 0; i < retArray.size(); i++) {
                        JSONObject retOne = retArray.getJSONObject(i);
                        String msgId = retOne.getString("msgId");
                        String status = retOne.getString("status");
                        try {
                            LOG.info("--------开始更新短信---------："+ msgId);
                            querySendStatus(msgId, status);
                            LOG.info("--------结束更新短信---------："+ msgId);
                        } catch (XbbException e) {
                            e.printStackTrace();
                            LOG.error("获取短信状态回调失败", e);
                        }
                    }
                }
            }
        });
    }

    /**
     * 2：营销号
     *
     * @return
     */
    public JSONObject getStatus() {
        Map<String, Object> param = new HashMap<String, Object>(16);
        String account = "M1252607";
        String password = "2lywWNBgCZfb66";
        param.put("account", account);
        param.put("password", password);
        param.put("count", 100);
        String ret = OkHttpUtil.post(GET_STATUS_URI, JSON.toJSONString(param));
        return JSONObject.parseObject(ret);
    }

    /**
     * 1：调试号--正在用
     *
     * @return
     */
    public JSONObject getStatusMsg() {
        Map<String, Object> param = new HashMap<String, Object>(16);
        String account = "N8010355";
        String password = "p84jDXw1A";
        param.put("account", account);
        param.put("password", password);
        param.put("count", 100);
        String ret = OkHttpUtil.post(GET_STATUS_URI, JSON.toJSONString(param));
        return JSONObject.parseObject(ret);
    }

    /**
     * 更新短信状态
     *
     * @param msgId      短信编号
     * @param statusCode 创蓝提供的短信状态
     * @throws XbbException
     */
    private void querySendStatus(String msgId, String statusCode) throws XbbException {
        String statusMemo = "";
        int status = SmsStatusEnum.FAILURE_SEND.getCode();
        switch (statusCode) {
            case "DELIVRD":
                status = SmsStatusEnum.SUCCESS_SEND.getCode();
                statusMemo = "短消息转发成功";
                break;
            case "EXPIRED":
                statusMemo = "短消息超过有效期";
                break;
            case "UNDELIV":
                statusMemo = "短消息是不可达的";
                break;
            case "UNKNOWN":
                statusMemo = "未知短消息状态";
                break;
            case "REJECTD":
                statusMemo = "短消息被短信中心拒绝";
                break;
            case "DTBLACK":
                statusMemo = "目的号码是黑名单号码";
                break;
            case "ERR:104":
                statusMemo = "系统忙";
                break;
            case "REJECT":
                statusMemo = "审核驳回";
                break;
            default:
                statusMemo = "网关内部状态";
                break;
        }
        try {
            Map<String, Object> param = new HashMap<>(16);
            param.put("msgId", msgId);
            List<SmsStatusEntity> lists = smsStatusModel.findEntitys(param);
            long statusTime = DateUtil.getInt();
            if (lists.size() > 0) {
                SmsStatusEntity entity = lists.get(0);
                entity.setStatus(status);
                entity.setStatusCode(statusCode);
                entity.setStatusMemo(statusMemo);
                entity.setStatusTime(statusTime);
                smsStatusModel.update(entity);
            } else {
                // 数据有问题
                LOG.error("创蓝回调数据与库中数据不符，msgid:" + msgId);
            }
        } catch (Exception e) {
            LOG.error("记录下当前的msgId和statusCode:" + msgId, statusCode);
            LOG.error("获取短信状态回调失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
    }
}
